package com.me.study.concurrent.threadUtil;

import com.me.common.util.SleepUtil;

import java.time.LocalTime;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;

/**
 * <pre> Fork/Join 框架测试：无返回值的任务 -- RecursiveAction </pre>
 * 1, 当业务处理很简单，抵消不了多线程上下文切换带来的性能损耗时，单线程性能更好！
 * <blockquote>
 *      比如：注释掉 SleepUtil.ms(1);
 * </blockquote>
 * 2, 当业务处理变得复杂时，才能发挥分治算法的优势！
 *
 * @author ME
 * @date 2019/2/2 16:08
 */
public class TestForkJoinPool2 {

    private static final int ARRAY_LENGTH = 100;
    private static final int[] INT_ARR = new int[ARRAY_LENGTH];

    static {
        for (int i = 0; i < INT_ARR.length; ) {
            INT_ARR[i] = ++i;
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        SubTask task = new SubTask(INT_ARR, 0, INT_ARR.length - 1);
        /**
         * 提交任务3个方法 execute、invoke、submit 的区别：
         *      execute(ForkJoinTask) 异步执行 task，无返回值
         * 	    invoke(ForkJoinTask) 自带 join(), task会被同步到主进程。阻塞等待任务完成并返回结果，或者抛出异常
         *      submit(ForkJoinTask) 异步执行，且返回 Task返回值，可通过 task.get() 实现同步到主线程
         */
        System.out.println(LocalTime.now());
        pool.execute(task);
        System.out.println(LocalTime.now() + "      你猜 main线程有没有被阻塞");

        SleepUtil.seconds(10);
    }

    /**
     * 无返回值的 Fork/Join 子任务
     */
    private static class SubTask extends RecursiveAction {
        /**
         * 任务的临界数量，Fork/Join 子任务中任务数量超过临界点就需要再次拆分
         */
        private static final int THRESHOLD = ARRAY_LENGTH / 10;
        /**
         * 原数组的指针，避免了复制的消耗
         */
        private final int[] src;
        /**
         * 当前任务的开始下标
         */
        private final int startInd;
        /**
         * 当前任务的结束下标
         */
        private final int endInd;

        public SubTask(int[] src, int startInd, int endInd) {
            this.src = src;
            this.startInd = startInd;
            this.endInd = endInd;
        }

        @Override
        protected void compute() {
            // if (endInd - startInd + 1 <= THRESHOLD) {
            if (endInd - startInd < THRESHOLD) {
                // 任务数量小于临界点数量，直接执行
                for (int index = startInd; index <= endInd; index++) {
                    System.out.println("do something：" + src[index]);
                }
            } else {
                // 任务数量大于于临界点数量，直接执行
                int middle = (endInd + startInd) / 2;
                SubTask task1 = new SubTask(src, startInd, middle);
                SubTask task2 = new SubTask(src, middle + 1, endInd);
                invokeAll(task1, task2);
                // task1.fork();
                // task2.fork();
            }
        }
    }

}
